package com.chengv.redismq.core;

import cn.hutool.core.collection.CollUtil;
import com.chengv.redismq.annotation.RedisMQMessageListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.lang.NonNull;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.AnnotatedElement;
import java.util.*;
import java.util.stream.Collectors;

/**
 * {@link RedisMQMessageListener} 注解后置处理器
 *
 * @author chengv
 */
@Slf4j
public class RedisMQMessageListenerAnnotationPostProcessor
        implements ApplicationContextAware, BeanPostProcessor, InitializingBean {

    private ApplicationContext applicationContext;
    private RedisMQDelayMessageScheduledTaskRegistrar delayMessageScheduledTaskRegistrar;
    private RedisMQStreamListenerRegistrar streamMessageListenerRegistrar;


    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void afterPropertiesSet() {
        this.streamMessageListenerRegistrar = this.applicationContext.getBean(RedisMQStreamListenerRegistrar.class);
        this.delayMessageScheduledTaskRegistrar = this.applicationContext.getBean(RedisMQDelayMessageScheduledTaskRegistrar.class);
    }

    @Override
    public Object postProcessAfterInitialization(@NonNull Object bean, @NonNull String beanName) throws BeansException {
        Class<?> targetClass = AopUtils.getTargetClass(bean);
        ReflectionUtils.doWithMethods(targetClass, method -> {
            // 获取方法上的 RedisMQMessageListener 注解
            List<RedisMQMessageListener> annotations = findAnnotations(method);
            if (CollUtil.isNotEmpty(annotations)) {
                // 注册 消息监听器
                if (streamMessageListenerRegistrar != null) {
                    annotations.forEach(annotation -> streamMessageListenerRegistrar.register(bean, method, annotation));
                }

                // 注册 延迟消息调度任务
                if (delayMessageScheduledTaskRegistrar != null) {
                    annotations.forEach(annotation -> delayMessageScheduledTaskRegistrar.register(annotation));
                }
            }
        }, ReflectionUtils.USER_DECLARED_METHODS);
        return bean;
    }

    private List<RedisMQMessageListener> findAnnotations(AnnotatedElement element) {
        return MergedAnnotations.from(element, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY)
                .stream(RedisMQMessageListener.class).map(MergedAnnotation::synthesize).collect(Collectors.toList());
    }
}
